/*
 * CCVisu is a tool for visual graph clustering
 * and general force-directed graph layout.
 * This file is part of CCVisu.
 *
 * Copyright (C) 2005-2011  Dirk Beyer
 *
 * CCVisu is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * CCVisu is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with CCVisu; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Please find the GNU Lesser General Public License in file
 * license_lgpl.txt or http://www.gnu.org/licenses/lgpl.txt
 *
 * Dirk Beyer    (firstname.lastname@uni-passau.de)
 * University of Passau, Bavaria, Germany
 */
package org.sosy_lab.ccvisu.ui.controlpanel;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.sosy_lab.ccvisu.CCVisuOptions;
import org.sosy_lab.ccvisu.clustering.ClustererBase;
import org.sosy_lab.ccvisu.clustering.ClustererMinDist;
import org.sosy_lab.ccvisu.clustering.ClustererMinDistPerc;
import org.sosy_lab.ccvisu.clustering.CopyOfClustererMinDistPerc;
import org.sosy_lab.ccvisu.ui.helper.ClassCellRenderer;
import org.sosy_lab.common.LogManager;
import org.sosy_lab.util.interfaces.WorkerManager;

public class ToolPanelClusterer extends ControlPanel {

  private static final long serialVersionUID        = 1L;

  // generic since Java 7; we require Java 6; see svn r825 for comparison
  @SuppressWarnings("rawtypes")
  private JComboBox         clustererClassComboBox  = new JComboBox();

  private JSpinner          numOfClustersSpinner    = new JSpinner();
  private JSlider           mergeDistanceSlider     = new JSlider(0, 100);
  private JLabel            mergeDistanceValueLabel = new JLabel();
  private JSlider           minDistanceSlider       = new JSlider(0, 100);
  private JLabel            minDistanceValueLabel   = new JLabel();
  private JButton           runButton               = new JButton("Run clusterer");
  private CCVisuOptions     options                 = null;
  private WorkerManager     workerManager           = null;

  private final LogManager logger;

  public ToolPanelClusterer(CCVisuOptions options, LogManager logger,
      WorkerManager workerManager) {

    this.options = options;
    this.workerManager = workerManager;
    this.logger = logger;

    initComponents();
  }

  private void initComponents() {
    setLayout(new BorderLayout());
    setMinimumSize(new Dimension(500, 150));

    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new GridBagLayout());
    add(mainPanel, BorderLayout.CENTER);

    JPanel mergeDistancePanel = new JPanel(new BorderLayout());
    mergeDistancePanel.add(mergeDistanceSlider, BorderLayout.CENTER);
    mergeDistancePanel.add(mergeDistanceValueLabel, BorderLayout.EAST);

    JPanel minDistancePanel = new JPanel(new BorderLayout());
    minDistancePanel.add(minDistanceSlider, BorderLayout.CENTER);
    minDistancePanel.add(minDistanceValueLabel, BorderLayout.EAST);

    addOptionControls(mainPanel, "Clusterer class:", clustererClassComboBox);
    addOptionControls(mainPanel, "Number of partitions (at least):", numOfClustersSpinner);
    addOptionControls(mainPanel, "Merge partitions within distance (%):", mergeDistancePanel);
    addOptionControls(mainPanel, "Minimal cluster distance (%):", minDistancePanel);

    JPanel controlPanel = new JPanel();
    controlPanel.add(runButton);
    add(controlPanel, BorderLayout.SOUTH);

    // Fill components…
    mergeDistanceSlider.setValue(5);
    mergeDistanceSlider.setPaintTicks(false);
    mergeDistanceSlider.setPaintLabels(false);
    mergeDistanceSlider.addChangeListener(new ChangeListener() {
      @Override
      public void stateChanged(ChangeEvent pE) {
        mergeDistanceValueLabel.setText(String.format("%d", mergeDistanceSlider.getValue()));
      }
    });

    minDistanceSlider.setValue(40);
    minDistanceSlider.setPaintTicks(false);
    minDistanceSlider.setPaintLabels(false);
    minDistanceSlider.addChangeListener(new ChangeListener() {
      @Override
      public void stateChanged(ChangeEvent pE) {
        minDistanceValueLabel.setText(String.format("%d", minDistanceSlider.getValue()));
      }
    });

    fillClusterClassComboBox();

    // Bind actions...
    runButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent pE) {
        runClusteringAction(pE);
      }
    });
  }

  // JComboBox is generic since Java 7; we require Java 6
  // This method was extracted to suppress the warnings only for these lines of
  // code.  See svn r825 for comparison.
  @SuppressWarnings("unchecked")
  private void fillClusterClassComboBox() {
    clustererClassComboBox.addItem(ClustererMinDistPerc.class);
    clustererClassComboBox.addItem(CopyOfClustererMinDistPerc.class);
    clustererClassComboBox.addItem(ClustererMinDist.class);
    clustererClassComboBox.setRenderer(new ClassCellRenderer());
  }

  protected ClustererBase createParameterizedClusterer() throws ClassNotFoundException {
    int numOfclusters = (Integer)numOfClustersSpinner.getValue();
    double mergeDistanceFract = mergeDistanceSlider.getValue() / 100.0;
    double minDistanceFract = minDistanceSlider.getValue() / 100.0;

    // JComboBox is generic since Java 7; we require Java 6;
    // see svn r825 for comparison
    @SuppressWarnings("rawtypes")
    Class<?> clustererClass = (Class)clustererClassComboBox.getSelectedItem();
    if (clustererClass == ClustererMinDist.class) {
      return new ClustererMinDist(options.getGraph(), logger, numOfclusters);
    } else if (clustererClass == CopyOfClustererMinDistPerc.class) {
      return new CopyOfClustererMinDistPerc(options.getGraph(), logger, numOfclusters,
          mergeDistanceFract, minDistanceFract);
    } else if (clustererClass == ClustererMinDistPerc.class) {
      return new ClustererMinDistPerc(options.getGraph(), logger, numOfclusters,
          mergeDistanceFract, minDistanceFract);
    } else {
      throw new ClassNotFoundException("No valid clusterer selected!");
    }
  }

  private void runClusteringAction(ActionEvent ev) {
    try {
      ClustererBase clusterer = createParameterizedClusterer();
      options.getGraph().clearClustering();
      workerManager.addAndRunTask(clusterer, "Clusterer");
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
  }
}
